//
//  NGAppDelegate.m
//  Mobil Izleme
//
//  Created by Mehmet Sinan Şahin on 1/2/12.
//  Copyright (c) 2012 netgis. All rights reserved.
//


#import "NGAppDelegate.h"
#import "WebServiceCaller.h"
#import "SetLocationRequest.h"
#import "SetLocationsRequest.h"
#import "NGUtility.h"
#import "GPS.h"
#import "NGMainViewController.h"
#import "NGTestLogViewController.h"
#import "NGNotPostedLocationsViewController.h"
#import "NGMessageListViewController.h"
#import "SharedPrefs.h"
#import "Reachability.h"
#import "NGDBHelper.h"
#import "NGDeviceData.h"
#import "NSString+Extensions.h"
#import "NGUtility.h"
#import "LoginViewController.h"
#import "AboutViewController.h"
#import "UncaughtExceptionHandler.h"
#import "ServiceAgreementViewController.h"

@interface NGAppDelegate()

- (void)handleAggrement;
- (void)login;
- (void)initializeGPS;

@end

@implementation NGAppDelegate

@synthesize window = _window;
//@synthesize viewController = _viewController;
@synthesize tabBarController = _tabBarController;
@synthesize mainViewController;
@synthesize flagNoConnectionAlertShown;

#if _THIS
@synthesize locationManager;
#endif

- (void)startUpdates: (NSString *)mode {
    
#if USE_THIS_LOCATION_MANAGER
#ifdef FAKE_CORE_LOCATION
    NSLog(@"%@", @"FTLocationSimulator running");
    self.locationManager = [[[FTLocationSimulator alloc] init] autorelease];
#else
    self.locationManager = [[[CLLocationManager alloc] init] autorelease];
#endif
    self.locationManager.delegate = self; // Tells the location manager to send updates to this object
#endif
    
    // Use the highest possible accuracy and combine it with additional sensor data.
    // This level of accuracy is intended for use in navigation applications that require precise
    // position information at all times and are intended to be used only while the device is plugged in.
    //
#if USE_THIS_LOCATION_MANAGER
    self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
    
    if ([@"significant" isEqualToString:mode]) {
        [self.locationManager startMonitoringSignificantLocationChanges];        
    } else if ([@"standart" isEqualToString:mode]) {
        [self.locationManager startUpdatingLocation];    
    } else {
        [self.locationManager startUpdatingLocation];            
    }
#endif    
}

- (void)networkConnectionReachabilityInitialize {
    // Observe the kNetworkReachabilityChangedNotification. When that notification is posted, the
    // method "reachabilityChanged" will be called. 
    [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(reachabilityChanged:) name: kReachabilityChangedNotification object: nil];
    
    internetReach = [[Reachability reachabilityForInternetConnection] retain];
	[internetReach startNotifier];
}

#pragma mark - Reachability callback

//Called by Reachability whenever status changes.
- (void) reachabilityChanged: (NSNotification* )note
{
	Reachability* curReach = [note object];
	NSParameterAssert([curReach isKindOfClass: [Reachability class]]);
    NetworkStatus netStatus = [curReach currentReachabilityStatus];
    if (netStatus != NotReachable) {
        NSLog(@"Internet Baglantisi yapildi.");
        //[self sendUnsentLocationToServer:FALSE];
    } else {
        NSLog(@"Internet Baglantisi kesildi.");
        [NGAppDelegate alertForNoInternetConnection];
    }
}

#pragma mark - Tabbar controll delegate

- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
    if ([viewController.nibName isEqualToString:@"NGNotPostedLocationsViewController"] || [viewController.nibName isEqualToString:@"NGMessageListViewController"]) {
        //[self.tabBarController.tabBar setHidden:YES];
        [self makeTabBarHidden:TRUE];
    } else {
        [self makeTabBarHidden:FALSE];
    }
}

- (void)makeTabBarHidden:(BOOL)hide {
	// Custom code to hide TabBar
    
	UIView *contentView;
    UITabBarController *tabBarController = self.tabBarController;
	if ( [[tabBarController.view.subviews objectAtIndex:0] isKindOfClass:[UITabBar class]] ) {
		contentView = [tabBarController.view.subviews objectAtIndex:1];
	} else {
		contentView = [tabBarController.view.subviews objectAtIndex:0];
	}
    
	if (hide) {
		contentView.frame = tabBarController.view.bounds;
	}
	else {
		contentView.frame = CGRectMake(tabBarController.view.bounds.origin.x,
                                       tabBarController.view.bounds.origin.y,
                                       tabBarController.view.bounds.size.width,
                                       tabBarController.view.bounds.size.height - tabBarController.tabBar.frame.size.height);
	}
    
	tabBarController.tabBar.hidden = hide;
}



#pragma mark - LoginWindowClose methods
-(void) loginClose {
    NSLog(@"Login closed.");
    
}

#pragma mark - ServiceAgreementWindowClose methods

-(void) aggrementClose:(BOOL)acceptance {
    [SharedPrefs setServiceAggrementStatus:acceptance];
    if (acceptance) {
        [self login];        
    }
}

- (void)handleAggrement {
    if (![SharedPrefs isServiceAggreed]){
        ServiceAgreementViewController *ctrl = [[[ServiceAgreementViewController alloc] initWithNibName:@"ServiceAgreementViewController" bundle:nil] autorelease];
        [ctrl setCloseCallbackTarget:self]; //aggrementClose(BOOL) method should be defined
        self.window.rootViewController = ctrl;  
    } else {
        [self login];
    }
}

- (void)login {
    LoginViewController *login = [[[LoginViewController alloc] initWithNibName:@"LoginViewController" bundle:nil] autorelease];
    [login setCloseCallbackTarget:self];
    self.window.rootViewController = login;  
}

- (void)enter {
    
    // Override point for customization after application launch.
    UIViewController    *viewControllerMain, 
                        *viewControllerAbout, 
                        *viewControllerNotPostedList,
                        *viewControllerMessageList;
    
    NSString *aboutViewNibName = @"AboutViewController";
    
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
        viewControllerMain = [[[NGMainViewController alloc] initWithNibName:@"NGMainViewController" bundle:nil] autorelease];
        viewControllerAbout = [[[AboutViewController alloc] initWithNibName:aboutViewNibName bundle:nil] autorelease];
        viewControllerNotPostedList = [[[NGNotPostedLocationsViewController alloc] initWithNibName:@"NGNotPostedLocationsViewController" bundle:nil] autorelease];
        viewControllerMessageList = [[[NGMessageListViewController alloc] initWithNibName:@"NGMessageListViewController" bundle:nil] autorelease];
    } else {
        viewControllerMain = [[[NGMainViewController alloc] initWithNibName:@"NGMainViewController" bundle:nil] autorelease];
        viewControllerAbout = [[[AboutViewController alloc] initWithNibName:aboutViewNibName bundle:nil] autorelease];
        viewControllerNotPostedList = [[[NGNotPostedLocationsViewController alloc] initWithNibName:@"NGNotPostedLocationsViewController" bundle:nil] autorelease];
        viewControllerMessageList = [[[NGMessageListViewController alloc] initWithNibName:@"NGMessageListViewController" bundle:nil] autorelease];
    }
    self.tabBarController = [[[UITabBarController alloc] init] autorelease];
    self.tabBarController.viewControllers = [NSArray arrayWithObjects:
                                             viewControllerMain,
                                             viewControllerAbout, 
                                             viewControllerNotPostedList,
                                             viewControllerMessageList,
                                             nil];
    
    self.mainViewController = viewControllerMain;
    
    long newMessageNumber =[[NGDBHelper openDatabase] howManyNewMessages]; 
    [self setMessageBadge:newMessageNumber];
    
    self.tabBarController.delegate = self;
    self.window.rootViewController = self.tabBarController;
    
    [self sendAppStarted: viewControllerMain];
    
    //Uygulama açıldığında gönderilemeyen konumları göndermeye çalış
    //[self sendUnsentLocationToServer:TRUE];
    
    [self networkConnectionReachabilityInitialize];
    [self initializeGPS];
}

- (void)initializeGPS {
    [[GPS get] start];
    //[self.window makeKeyAndVisible];
    
    #if USE_THIS_LOCATION_MANAGER == FALSE
        GPS *gps = [GPS get];
        [gps init];
        gps.locationUpdatedDelegate = self.mainViewController;
        if (gps.gps_is_on) {
            [gps start];
        } else {
            NSLog(@"NGAppDelegate -> GPS IS OFF");
        }
    #else
        [self startUpdates:@"standart"];    //significant için @"significant" gönder
        //http://developer.apple.com/library/ios/#documentation/UserExperience/Conceptual/LocationAwarenessPG/CoreLocation/CoreLocation.html#//apple_ref/doc/uid/TP40009497-CH2-SW10
        //background için
        //http://developer.apple.com/library/ios/#documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html#//apple_ref/doc/uid/TP40007072-CH4-SW25    
    #endif
}

- (void)installUncaughtExceptionHandler
{
	InstallUncaughtExceptionHandler();
}

#pragma mark - View lifecycle

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [SharedPrefs registerDefaults];
    NSString *serviceUrl = [SharedPrefs getServiceUrl];
    [SharedPrefs setServiceUrl:serviceUrl];
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults synchronize];
    
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
    
    self.flagNoConnectionAlertShown = FALSE;

    if (TRUE) {
        [self handleAggrement];
    } else {
        [self enter];
    }
    [self.window makeKeyAndVisible];

    [self performSelector:@selector(installUncaughtExceptionHandler) withObject:nil afterDelay:0];

    return YES;
}

/*
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
	NSLog(@"Launching application with %@", launchOptions);
    
	[[UIDevice currentDevice] setBatteryMonitoringEnabled:YES];
	_set_globals();
    
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
    // Override point for customization after application launch.
    //self.viewController = [[[NGViewController alloc] initWithNibName:@"NGViewController" bundle:nil] autorelease];
    
    UIViewController *viewControllerMain = [[[NGViewController alloc] initWithNibName:@"NGViewController" bundle:nil] autorelease];
    UIViewController *viewControllerYardim = [[[NGYardimController alloc] initWithNibName:@"NGYardimController" bundle:nil] autorelease];
    
    self.tabBarController = [[[UITabBarController alloc] initWithNibName:@"TabbarController" bundle:nil] autorelease];
    self.tabBarController.viewControllers = [NSArray arrayWithObjects:viewControllerMain, viewControllerYardim, nil];    
    
    self.window.rootViewController = self.tabBarController;
    [self.window makeKeyAndVisible];
    
#if USE_THIS_LOCATION_MANAGER == FALSE
    GPS *gps = [GPS get];
    if (gps.gps_is_on) {
        //[gps start];
    } else {
        NSLog(@"GPS IS OFF");
    }
#else    
    [self startUpdates:@"standart"];    //significant için @"significant" gönder
    //http://developer.apple.com/library/ios/#documentation/UserExperience/Conceptual/LocationAwarenessPG/CoreLocation/CoreLocation.html#//apple_ref/doc/uid/TP40009497-CH2-SW10
    //background için
    //http://developer.apple.com/library/ios/#documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html#//apple_ref/doc/uid/TP40007072-CH4-SW25    
#endif
    return YES;
}
*/
 
- (void)applicationWillResignActive:(UIApplication *)application
{
    /*
     Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
     Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
     */
    //[[GPS get] set_accuracy:MEDIUM_ACCURACY reason:@"Lost focus."];
}


- (void)applicationDidEnterBackground:(UIApplication *)application
{
    /*
     Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 
     If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
     */
    //[[GPS get] set_accuracy:MEDIUM_ACCURACY reason:@"Entering background mode."];
    NSLog(@"Entering background mode.");    
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
    /*
     Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
     */
    //[[GPS get] set_accuracy:HIGH_ACCURACY reason:@"Gained focus."];
    [UIApplication sharedApplication].applicationIconBadgeNumber = 0;
    //[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    /*
     Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
     */
    //[[GPS get] set_accuracy:HIGH_ACCURACY reason:@"Raising from background."];
}

- (void)applicationWillTerminate:(UIApplication *)application
{
    /*
     Called when the application is about to terminate.
     Save data if appropriate.
     See also applicationDidEnterBackground:.
     */
	if ([GPS get].gps_is_on) {
        NSLog(@"Terminating app while GPS was on...");
    }

    [self sendAppTerminated];
    
	//[db_ flush];
	//[db_ close];
    
	// Save pending changes to user defaults.
	[SharedPrefs sync];  
}

#pragma mark - send locations

-(void) sendAppTerminated {
    
    //TODO son konumu al
    NGLocation *location = [NGLocation alloc];
	location.lat = 99999999;
	location.lon = 99999999;
	location.speed = @"0";
	location.status = UYGULAMA_KAPANDI;
	location.tarihSaat = [NSDate date];
	location.deviceCode = [NGUtility getDeviceId];
    
    [[NGDBHelper openDatabase] insertLocationForUnsent:location];
    /*
    SetLocationRequest *request = [[SetLocationRequest alloc] initWithLocation:location];
    [WebServisCaller callWebService:request target:request];
    NSLog(@"App terminated, send UYGULAMA_KAPANDI to server.");
     */
}

-(void) sendAppStarted: (id) targetForUI {
    //TODO son konumu al
    NGLocation *location = [NGLocation alloc];
	location.lat = 99999999;
	location.lon = 99999999;
	location.speed = @"0";
	location.status = UYGULAMA_ACILDI;
	location.tarihSaat = [NSDate date];
	location.deviceCode = [NGUtility getDeviceId];
    
    SetLocationRequest *request = [[SetLocationRequest alloc] initWithLocation:location];
    request.locationUpdatedDelegate = targetForUI;
    
    [WebServisCaller callWebService:request target:request];
    NSLog(@"App terminated, send UYGULAMA_ACILDI to server.");    
}

- (void)sendUnsentLocationToServer:(BOOL)lookforReachability {
    if (lookforReachability) {
        if ([[Reachability reachabilityForInternetConnection] currentReachabilityStatus] == NotReachable) {
            return;
        }
    }
    
    /*
    if (TRUE) { //TODO kaldır signal 11 için
        return;
    }
    */
    
    //read unsent location from database 
    NGDBHelper *db = [NGDBHelper openDatabase];
    NSArray *unsentLocations = [db listUnsentLocations]; //must be release manually
    
    if ([unsentLocations count] > 0) {
        NSMutableArray *array  = [[NSMutableArray alloc] initWithCapacity:[unsentLocations count]];
        for (NGLocation *location in unsentLocations) {
            location.deviceCode = [NGUtility getDeviceId];
            NSLog(@"Retain Count(Before): %d", [location retainCount]);
            [location retain];
            NSLog(@"Retain Count(After): %d", [location retainCount]);
            [array addObject:[[NGDeviceData alloc] initWithNGLocation:location]];
            [location release];
            NSLog(@"Retain Count(After Release): %d", [location retainCount]);
        }
        
        [unsentLocations release];

        SetLocationsRequest *request = [[SetLocationsRequest alloc] initWithLocations:array];
        [WebServisCaller callWebServiceSetLocations:request target:request];
    }
}


#pragma mark - Location Manager delegates


- (void)locationManager:(CLLocationManager *)manager
    didUpdateToLocation:(CLLocation *)newLocation
           fromLocation:(CLLocation *)oldLocation
{
    NSDate* eventDate = newLocation.timestamp;
    NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
    if (abs(howRecent) < 15.0)
    {
        if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {
            UILocalNotification *localNotification = [[[UILocalNotification alloc] init] autorelease];
            if (!localNotification) {
                // Current date
                NSDate *date = [NSDate date]; 
                
                // Add one minute to the current time
                NSDate *dateToFire = [date dateByAddingTimeInterval:60];
                
                // Set the fire date/time
                [localNotification setFireDate:dateToFire];
                [localNotification setTimeZone:[NSTimeZone defaultTimeZone]];
                
                // Create a payload to go along with the notification
                NSArray *array = [NSArray arrayWithObjects:@"Value 1", @"Value 2", nil];
                NSDictionary *data = [NSDictionary dictionaryWithObject:array forKey:@"payload"];
                [localNotification setUserInfo:data];
                
                [localNotification setApplicationIconBadgeNumber:[[UIApplication sharedApplication] applicationIconBadgeNumber] + 1];
                [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];                
            }       
            NSLog(@"background");
        }
        
        NSLog(@"latitude %+.6f, longitude %+.6f\n",
              newLocation.coordinate.latitude,
              newLocation.coordinate.longitude);
        
        if ([SharedPrefs isSendToServer]) {
            [self sendLocationToServer:newLocation];
            NSLog(@"SEND TO SERVER: YESx");            
        } else {
            NSLog(@"SEND TO SERVER: NOx");            
        }
    }    
}

- (void)sendLocationToServer:(CLLocation *)location {
    NSLog(@"NGAppDelegate Sending to server.....");
    NGLocation *ngLocation = [NGLocation initWithCLLocation:location];
    SetLocationRequest *request = [[SetLocationRequest alloc] initWithLocation:ngLocation];
    [WebServisCaller callWebService:request target:request];
}

- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
    NSLog(@"Received local notification %@", notification);
}

#pragma mark Global functions

BOOL g_is_multitasking = NO;
BOOL g_location_changes = NO;
BOOL g_region_monitoring = NO;

/** Updates the state of some global variables.
 * These are variables like g_is_multitasking, which can be read
 * by any one any time. Call this function whenever you want,
 * preferably during startup.
 */
static void _set_globals(void)
{
	UIDevice* device = [UIDevice currentDevice];
    
	if ([device respondsToSelector:@selector(isMultitaskingSupported)])
		g_is_multitasking = device.multitaskingSupported;
	else
		g_is_multitasking = NO;
    
	g_location_changes = NO;
	SEL getter = @selector(significantLocationChangeMonitoringAvailable);
	if ([CLLocationManager respondsToSelector:getter])
		if ([CLLocationManager performSelector:getter])
			g_location_changes = YES;
    
	getter = @selector(regionMonitoringAvailable);
	if ([CLLocationManager respondsToSelector:getter])
		if ([CLLocationManager performSelector:getter])
			g_region_monitoring = YES;
}

+ (NGAppDelegate *) getApp {
    return (NGAppDelegate *) [[UIApplication sharedApplication] delegate];
}

/**
 * when message is arrived this method should be called for updating badge number of messages tab
 */
- (void) setMessageBadge:(int)numberOfMessage {
    
    NSString *badgeValue = nil;
    if (numberOfMessage > 0 ){
        badgeValue = [NSString stringWithFormat:@"%d", numberOfMessage];
    }
    
    [[[[self.tabBarController viewControllers] objectAtIndex:3] tabBarItem] setBadgeValue:badgeValue];    
}

+ (void) alertForNoInternetConnection {
    NGAppDelegate *app = [NGAppDelegate getApp];
    if (!app.flagNoConnectionAlertShown) {
        UIAlertView *alert = [[UIAlertView alloc]
                              initWithTitle: TTLocalizedString(@"Connection Error", @"")
                              message: TTLocalizedString(@"No Internet Connection", @"")
                              delegate:app
                              cancelButtonTitle:TTLocalizedString(@"OK", @"")
                              otherButtonTitles:nil];
        [alert show];
        [alert release];
        app.flagNoConnectionAlertShown = TRUE;
    }
    NSLog(@"No internet connection");
}

// Called when no connection alert button is touched
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
    
    switch (buttonIndex) {          
        case 1: {
            self.flagNoConnectionAlertShown = FALSE;
        } break;
    }
}

- (void)dealloc
{
    [_window release];
    //[_viewController release];
    [_tabBarController release];
    [super dealloc];
}

@end
